package com.felkertech.cumulustv.utils;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.media.tv.TvContract;
import android.net.Uri;
import android.os.Environment;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.customtabs.CustomTabsIntent;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.widget.Toast;

import com.felkertech.cumulustv.activities.CumulusVideoPlayback;
import com.felkertech.cumulustv.fileio.CloudStorageProvider;
import com.felkertech.cumulustv.plugins.CumulusChannel;
import com.felkertech.cumulustv.plugins.CumulusTvPlugin;
import com.felkertech.cumulustv.Intro.Intro;
import com.felkertech.cumulustv.services.CumulusJobService;
import com.felkertech.n.cumulustv.R;
import com.felkertech.cumulustv.activities.HomepageWebViewActivity;
import com.felkertech.cumulustv.activities.MainActivity;
import com.felkertech.cumulustv.model.ChannelDatabase;
import com.felkertech.cumulustv.model.JsonChannel;
import com.felkertech.cumulustv.receivers.GoogleDriveBroadcastReceiver;
import com.felkertech.cumulustv.tv.activities.LeanbackActivity;
import com.felkertech.settingsmanager.SettingsManager;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.drive.Drive;
import com.google.android.gms.drive.DriveApi;
import com.google.android.gms.drive.DriveFile;
import com.google.android.gms.drive.DriveId;
import com.google.android.gms.drive.OpenFileActivityBuilder;
import com.google.android.media.tv.companionlibrary.EpgSyncJobService;

import org.json.JSONException;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static com.felkertech.cumulustv.model.SuggestedChannels.getSuggestedChannels;

/**
 * Created by guest1 on 10/29/2015.
 */
public class ActivityUtils {
    private static final String TAG = ActivityUtils.class.getSimpleName();
    private static final boolean DEBUG = false;

    public static final int RESOLVE_CONNECTION_REQUEST_CODE = 100;
    public static final int REQUEST_CODE_CREATOR = 102;
    public static final int REQUEST_CODE_OPENER = 104;
    public static final int PERMISSION_EXPORT_M3U = 201;
    public static final ComponentName TV_INPUT_SERVICE = new ComponentName("com.felkertech.n.cumulustv",
            "com.felkertech.cumulustv.tv.CumulusTvTifService");

    public final static int LAST_GOOD_BUILD = 27;

    private static CloudStorageProvider mCloudStorageProvider = CloudStorageProvider.getInstance();
    private static GoogleApiClient mGoogleApiClient;

    public static GoogleApiClient getGoogleApiClient() {
        return mGoogleApiClient;
    }

    public static void openSuggestedChannels(final Activity mActivity, final GoogleApiClient gapi) {
        final CumulusChannel[] channels = getSuggestedChannels();
        ArrayList<String> channeltext = new ArrayList<String>();
        for(CumulusChannel j: channels) {
            channeltext.add(j.getName());
        }
        final String[] channelList = channeltext.toArray(new String[channeltext.size()]);
        new AlertDialog.Builder(mActivity)
                .setTitle(R.string.here_are_suggested_channels)
                .setItems(channelList, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        CumulusChannel j = channels[i];
                        addChannel(mActivity, gapi, j);
                    }
                })
                .show();
    }

    public static void addChannel(final Activity activity, GoogleApiClient gapi,
        CumulusChannel jsonChannel) {
        if (DEBUG) {
            Log.d(TAG, "I've been told to add " + jsonChannel.toString());
        }
        ChannelDatabase cd = ChannelDatabase.getInstance(activity);
        if(cd.channelExists(jsonChannel)) {
            Toast.makeText(activity, R.string.channel_dupe, Toast.LENGTH_SHORT).show();
        } else {
            try {
                if(jsonChannel.getName() != null) {
                    Toast.makeText(activity, activity.getString(R.string.channel_added,
                            jsonChannel.getName()), Toast.LENGTH_SHORT).show();
                }
                cd.add(jsonChannel);
                if (CloudStorageProvider.getInstance().isDriveConnected()) {
                    ActivityUtils.writeDriveData(activity, gapi);
                }
                GoogleDriveBroadcastReceiver.changeStatus(activity,
                        GoogleDriveBroadcastReceiver.EVENT_DOWNLOAD_COMPLETE);
                if (DEBUG) {
                    Log.d(TAG, "Added");
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Opens the correct intent to start editing the channel.
     *
     * @param activity The activity you're calling this from.
     * @param channelUrl The channel's media url.m
     */
    public static void editChannel(final Activity activity, final String channelUrl) {
        ChannelDatabase cdn = ChannelDatabase.getInstance(activity);
        final JsonChannel jsonChannel = cdn.findChannelByMediaUrl(channelUrl);
        if(channelUrl == null || jsonChannel == null) {
            try {
                Toast.makeText(activity, R.string.toast_error_channel_invalid,
                        Toast.LENGTH_SHORT).show();
            } catch (RuntimeException e) {
                Log.e(TAG, activity.getString(R.string.toast_error_channel_invalid));
            }
            return;
        }
        if(jsonChannel.getPluginSource() != null) {
            // Search through all plugins for one of a given source
            PackageManager pm = activity.getPackageManager();

            try {
                pm.getPackageInfo(jsonChannel.getPluginSource().getPackageName(),
                        PackageManager.GET_ACTIVITIES);
                // Open up this particular activity
                Intent intent = new Intent();
                intent.setComponent(jsonChannel.getPluginSource());
                intent.putExtra(CumulusTvPlugin.INTENT_EXTRA_ACTION, CumulusTvPlugin.INTENT_EDIT);
                Log.d(TAG, "Editing channel " + jsonChannel.toString());
                intent.putExtra(CumulusTvPlugin.INTENT_EXTRA_JSON, jsonChannel.toString());
                activity.startActivity(intent);
            }
            catch (PackageManager.NameNotFoundException e) {
                new AlertDialog.Builder(activity)
                        .setTitle(activity.getString(R.string.plugin_not_installed_title,
                                jsonChannel.getPluginSource().getPackageName()))
                        .setMessage(R.string.plugin_not_installed_question)
                        .setPositiveButton(R.string.download_app, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int which) {
                                Intent i = new Intent(Intent.ACTION_VIEW);
                                i.setData(Uri.parse("http://play.google.com/store/apps/details?id="
                                        + jsonChannel.getPluginSource().getPackageName()));
                                activity.startActivity(i);
                            }
                        })
                        .setNegativeButton(R.string.open_in_another_plugin, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                openPluginPicker(false, channelUrl, activity);
                            }
                        })
                        .show();
                Toast.makeText(activity, activity.getString(R.string.toast_msg_pack_not_installed,
                        jsonChannel.getPluginSource().getPackageName()),
                        Toast.LENGTH_SHORT).show();
                openPluginPicker(false, channelUrl, activity);
            }
        } else {
            if (DEBUG) {
                Log.d(TAG, "No specified source");
            }
            openPluginPicker(false, channelUrl, activity);
        }
    }

    /* DRIVE */
    public static void writeDriveData(final Activity context, GoogleApiClient gapi) {
        // Ask here for permission to storage
        PermissionUtils.requestPermissionIfDisabled(context,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                context.getString(R.string.permission_storage_rationale));
        if (PermissionUtils.isDisabled(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            new AlertDialog.Builder(context)
                    .setTitle(R.string.permission_not_allowed_error)
                    .setMessage(R.string.permission_not_allowed_text)
                    .setPositiveButton(R.string.permission_action_settings, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            Intent intent = new Intent();
                            intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                            Uri uri = Uri.fromParts("package", context.getPackageName(), null);
                            intent.setData(uri);
                        }
                    })
                    .setNegativeButton(R.string.ok, null)
                    .show();
        } else {
            actuallyWriteData(context, gapi);
        }
    }

    public static void writeDriveData(final Context context, GoogleApiClient gapi) {
        // This can crash
        actuallyWriteData(context, gapi);
    }

    private static void actuallyWriteData(final Context context, GoogleApiClient gapi) {
        DriveSettingsManager sm = new DriveSettingsManager(context);
        sm.setGoogleDriveSyncable(gapi, new DriveSettingsManager.GoogleDriveListener() {
            @Override
            public void onActionFinished(boolean cloudToLocal) {
                Log.d(TAG, "Action finished " + cloudToLocal);
            }
        });
        try {
            sm.writeToGoogleDrive(DriveId.decodeFromString(sm.getString(R.string.sm_google_drive_id)),
                    ChannelDatabase.getInstance(context).toString());
            GoogleDriveBroadcastReceiver.changeStatus(context,
                    GoogleDriveBroadcastReceiver.EVENT_UPLOAD_COMPLETE);

            final String info = TvContract.buildInputId(TV_INPUT_SERVICE);
            CumulusJobService.requestImmediateSync1(context, info, CumulusJobService.DEFAULT_IMMEDIATE_EPG_DURATION_MILLIS,
                    new ComponentName(context, CumulusJobService.class));
            Log.d(TAG, "Data actually written");
//            Toast.makeText(context, "Channels uploaded", Toast.LENGTH_SHORT).show();
        } catch(Exception e) {
            // Probably invalid drive id. No worries, just let someone know
            Log.e(TAG, e.getMessage() + "");
            Toast.makeText(context, R.string.invalid_file,
                    Toast.LENGTH_SHORT).show();
        }
    }

    public static void readDriveData(@NonNull Context context, GoogleApiClient gapi) {
        DriveSettingsManager sm = new DriveSettingsManager(context);
        sm.setGoogleDriveSyncable(gapi, null);
        DriveId did;
        try {
            did = DriveId.decodeFromString(sm.getString(R.string.sm_google_drive_id));
        } catch (Exception e) {
            Toast.makeText(context, R.string.invalid_file,
                    Toast.LENGTH_SHORT).show();
            return;
        }
        try {
            sm.readFromGoogleDrive(did, ChannelDatabase.KEY);
        } catch (ChannelDatabase.MalformedChannelDataException e) {
            Toast.makeText(context, R.string.drive_error_not_valid_json, Toast.LENGTH_SHORT).show();
        }
        GoogleDriveBroadcastReceiver.changeStatus(context,
                GoogleDriveBroadcastReceiver.EVENT_DOWNLOAD_COMPLETE);

        final String info = TvContract.buildInputId(TV_INPUT_SERVICE);
        if (AppUtils.isTV(context)) {
            CumulusJobService.requestImmediateSync1(context, info, CumulusJobService.DEFAULT_IMMEDIATE_EPG_DURATION_MILLIS,
                    new ComponentName(context, CumulusJobService.class));
        }
    }

    public static void createDriveData(Activity activity, GoogleApiClient gapi,
            final ResultCallback<DriveApi.DriveContentsResult> driveContentsCallback) {
        PermissionUtils.requestPermissionIfDisabled(activity,
                android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                activity.getString(R.string.permission_storage_rationale));
        if(gapi == null)
            gapi = mCloudStorageProvider.connect(activity);
        try {
            final GoogleApiClient finalGapi = gapi;
            new AlertDialog.Builder(activity)
                    .setTitle(R.string.create_sync_file_title)
                    .setMessage(R.string.create_sync_file_description)
                    .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            Drive.DriveApi.newDriveContents(finalGapi)
                                    .setResultCallback(driveContentsCallback);
                        }
                    })
                    .setNegativeButton(R.string.no, null)
                    .show();
        } catch(Exception ignored) {
            Toast.makeText(activity, "Error creating drive data: " + ignored.getMessage(),
                    Toast.LENGTH_SHORT).show();
        }
    }

    public static void switchGoogleDrive(Activity mActivity, GoogleApiClient gapi) {
        syncFile(mActivity, gapi);
    }

    public static void deleteChannelData(final Activity activity, GoogleApiClient gapi) {
        final DriveSettingsManager sm = new DriveSettingsManager(activity);
        sm.setGoogleDriveSyncable(gapi, null);
        new AlertDialog.Builder(activity)
                .setTitle(R.string.title_delete_all_channels)
                .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        ChannelDatabase.getInstance(activity).eraseData();
                        GoogleDriveBroadcastReceiver.changeStatus(activity,
                                GoogleDriveBroadcastReceiver.EVENT_DOWNLOAD_COMPLETE);
                        if (CloudStorageProvider.getInstance().isDriveConnected()) {
                            try {
                                DriveId did = DriveId.decodeFromString(sm.getString(R.string.sm_google_drive_id));
                                sm.writeToGoogleDrive(did,
                                        sm.getString(ChannelDatabase.KEY));
                            } catch (Exception e) {
                                Toast.makeText(activity, R.string.toast_error_driveid_invalid,
                                        Toast.LENGTH_SHORT).show();
                            }
                            sm.setString(R.string.sm_google_drive_id, "");
                        }
                        Toast.makeText(activity, R.string.toast_msg_channels_deleted,
                                Toast.LENGTH_SHORT).show();
                    }
                })
                .setNegativeButton(R.string.no, null)
                .show();
    }

    public static void syncFile(Activity activity, GoogleApiClient gapi) {
        if (DEBUG) {
        Log.d(TAG, "About to sync a file");
        }
        if (gapi == null && mCloudStorageProvider.connect(activity) != null) {
            gapi = mCloudStorageProvider.connect(activity);
        } else if(mCloudStorageProvider.connect(activity) == null) {
            // Is not existent
            Toast.makeText(activity, "There is no Google Play Service", Toast.LENGTH_SHORT).show();
            return;
        }
        if (gapi.isConnected()) {
            IntentSender intentSender = Drive.DriveApi
                    .newOpenFileActivityBuilder()
                    .setMimeType(new String[]{"application/json", "text/*"})
                    .build(gapi);
            try {
                if (DEBUG) {
                    Log.d(TAG, "About to start activity");
                }
                activity.startIntentSenderForResult(intentSender, REQUEST_CODE_OPENER, null, 0, 0,
                        0);
                if (DEBUG) {
                    Log.d(TAG, "Activity activated");
                }
            } catch (IntentSender.SendIntentException e) {
                if (DEBUG) {
                    Log.w(TAG, "Unable to send intent", e);
                }
                e.printStackTrace();
            }
        } else {
            Toast.makeText(activity, R.string.toast_msg_wait_google_api_client,
                    Toast.LENGTH_SHORT).show();
        }
    }

    /* LICENSES */
    public static void oslClick(Activity activity) {
        new AlertDialog.Builder(activity)
                .setTitle(R.string.software_licenses)
                .setMessage(GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(activity))
                .show();
    }

    /* PLUGIN INTERFACES */
    public static void openPluginPicker(final boolean newChannel, Activity activity) {
        openPluginPicker(newChannel, 0, activity);
    }

    public static void openPluginPicker(final boolean newChannel, final int index,
                                        final Activity activity) {
        try {
            ChannelDatabase cdn = ChannelDatabase.getInstance(activity);
            if(cdn.getJsonChannels().isEmpty()) {
                openPluginPicker(newChannel, JsonChannel.getEmptyChannel(), activity);
            } else {
                JsonChannel jsonChannel = cdn.getJsonChannels().get(index);
                openPluginPicker(newChannel, jsonChannel, activity);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public static void openPluginPicker(final boolean newChannel, final String channelUrl,
            final Activity activity) {
        ChannelDatabase cdn = ChannelDatabase.getInstance(activity);
        openPluginPicker(newChannel, cdn.findChannelByMediaUrl(channelUrl), activity);
    }

    public static void openPluginPicker(final boolean newChannel, final JsonChannel queriedChannel,
            final Activity activity) {
        final PackageManager pm = activity.getPackageManager();
        final Intent plugin_addchannel = new Intent(CumulusTvPlugin.ACTION_ADD_CHANNEL);
        final List<ResolveInfo> plugins = pm.queryIntentActivities(plugin_addchannel, 0);
        ArrayList<String> plugin_names = new ArrayList<String>();
        for (ResolveInfo ri : plugins) {
            plugin_names.add(ri.loadLabel(pm).toString());
        }
        String[] plugin_names2 = plugin_names.toArray(new String[plugin_names.size()]);
        if (DEBUG) {
            Log.d(TAG, "Load plugins " + plugin_names.toString());
        }
        if(plugin_names.size() == 1) {
            Intent intent = new Intent();
            if (newChannel) {
                if (DEBUG) {
                    Log.d(TAG, "Try to start ");
                }
                ResolveInfo plugin_info = plugins.get(0);
                if (DEBUG) {
                    Log.d(TAG, plugin_info.activityInfo.applicationInfo.packageName + " " +
                            plugin_info.activityInfo.name);
                }

                intent.setClassName(plugin_info.activityInfo.applicationInfo.packageName,
                        plugin_info.activityInfo.name);
                intent.putExtra(CumulusTvPlugin.INTENT_EXTRA_ACTION, CumulusTvPlugin.INTENT_ADD);
            } else {
                ResolveInfo plugin_info = plugins.get(0);
                Log.d(TAG, plugin_info.activityInfo.applicationInfo.packageName + " " +
                        plugin_info.activityInfo.name);
                intent.setClassName(plugin_info.activityInfo.applicationInfo.packageName,
                        plugin_info.activityInfo.name);
                intent.putExtra(CumulusTvPlugin.INTENT_EXTRA_ACTION, CumulusTvPlugin.INTENT_EDIT);
                intent.putExtra(CumulusTvPlugin.INTENT_EXTRA_JSON, queriedChannel.toString());
            }
            activity.startActivity(intent);
        } else {
            new AlertDialog.Builder(new ContextThemeWrapper(activity, R.style.CompatTheme))
                    .setTitle(R.string.choose_an_app)
//                    .setMessage(R.string.choose_default_app)
                    .setItems(plugin_names2, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Intent intent = new Intent();
                            if (newChannel) {
                                if (DEBUG) {
                                    Log.d(TAG, "Try to start");
                                }
                                ResolveInfo plugin_info = plugins.get(which);
                                if (DEBUG) {
                                    Log.d(TAG, plugin_info.activityInfo.applicationInfo.packageName
                                            + " " + plugin_info.activityInfo.name);
                                }

                                intent.setClassName(plugin_info.activityInfo.applicationInfo.packageName,
                                        plugin_info.activityInfo.name);

                                intent.putExtra(CumulusTvPlugin.INTENT_EXTRA_ACTION,
                                        CumulusTvPlugin.INTENT_ADD);
                            } else {
                                ResolveInfo plugin_info = plugins.get(which);
                                intent.setClassName(plugin_info.activityInfo.applicationInfo.packageName,
                                        plugin_info.activityInfo.name);
                                intent.putExtra(CumulusTvPlugin.INTENT_EXTRA_ACTION,
                                        CumulusTvPlugin.INTENT_EDIT);
                                intent.putExtra(CumulusTvPlugin.INTENT_EXTRA_JSON,
                                        queriedChannel.toString());
                            }
                            activity.startActivity(intent);
                        }
                    })
                    .show();
        }
    }

    public static void browsePlugins(final Activity activity) {
        //Same opening
        final PackageManager pm = activity.getPackageManager();
        final Intent plugin_addchannel = new Intent(CumulusTvPlugin.ACTION_ADD_CHANNEL);
        final List<ResolveInfo> plugins = pm.queryIntentActivities(plugin_addchannel, 0);
        ArrayList<String> plugin_names = new ArrayList<>();
        for (ResolveInfo ri : plugins) {
            plugin_names.add(ri.loadLabel(pm).toString());
        }
        String[] plugin_names2 = plugin_names.toArray(new String[plugin_names.size()]);

        new AlertDialog.Builder(new ContextThemeWrapper(activity, R.style.CompatTheme))
                .setTitle(R.string.installed_plugins)
                .setItems(plugin_names2, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        // Load the given plugin with some additional info
                        ChannelDatabase cd = ChannelDatabase.getInstance(activity);
                        String s = cd.toString();
                        Intent intent = new Intent();
                        if (DEBUG) {
                            Log.d(TAG, "Try to start");
                        }
                        ResolveInfo plugin_info = plugins.get(i);
                        Log.d(TAG, plugin_info.activityInfo.applicationInfo.packageName + " " +
                                plugin_info.activityInfo.name);

                        intent.setClassName(plugin_info.activityInfo.applicationInfo.packageName,
                                plugin_info.activityInfo.name);
                        intent.putExtra(CumulusTvPlugin.INTENT_EXTRA_ACTION,
                                CumulusTvPlugin.INTENT_EXTRA_READ_ALL);
                        intent.putExtra(CumulusTvPlugin.INTENT_EXTRA_ALL_CHANNELS, s);
                        activity.startActivity(intent);
                    }
                })
                .setPositiveButton(R.string.download_more_plugins, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int wh) {
                        Intent i = new Intent(Intent.ACTION_VIEW);
                        i.setData(Uri.parse(
                                "http://play.google.com/store/search?q=cumulustv&c=apps"));
                        activity.startActivity(i);
                    }
                })
                .show();
    }

    /* ACTIVITY CLONES */
    public static void launchLiveChannels(Activity activity) {
        Intent i = new Intent(Intent.ACTION_VIEW, TvContract.Channels.CONTENT_URI);
        try {
            activity.startActivity(i);
        } catch (Exception e) {
            Toast.makeText(activity, R.string.no_live_channels, Toast.LENGTH_SHORT).show();
        }
    }

    public static void onActivityResult(final Activity activity, GoogleApiClient gapi,
            final int requestCode, final int resultCode, final Intent data) {
        SettingsManager sm = new SettingsManager(activity);
        if(gapi == null) {
            gapi = mCloudStorageProvider.connect(activity);
        }
        mGoogleApiClient = gapi;
        switch (requestCode) {
            case RESOLVE_CONNECTION_REQUEST_CODE:
                if (resultCode == Activity.RESULT_OK) {
                    if (DEBUG) {
                        Log.d(TAG, "App connect +1");
                    }
                    gapi.connect();
                } else {
                    if (DEBUG) {
                        Log.d(TAG, "App cannot connect");
                    }
                    final GoogleApiClient finalGapi = gapi;
                    new AlertDialog.Builder(activity)
                            .setTitle(R.string.connection_issue_title)
                            .setMessage(R.string.connection_issue_description)
                            .setPositiveButton(R.string.ok, null)
                            .setNegativeButton(R.string.try_again, new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    finalGapi.connect();
                                }
                            })
                            .show();
                }
                break;
            case REQUEST_CODE_CREATOR:
                if (data == null || !gapi.isConnected()) {
                    // If op was canceled
                    return;
                }
                DriveId driveId = data.getParcelableExtra(
                        OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
                if (DEBUG) {
                    Log.d(TAG, driveId.encodeToString() + ", " + driveId.getResourceId() + ", " +
                            driveId.toInvariantString());
                }
                sm.setString(R.string.sm_google_drive_id, driveId.encodeToString());

                DriveFile file = Drive.DriveApi.getFile(gapi,
                        DriveId.decodeFromString(driveId.encodeToString()));
                //Write initial data
                ActivityUtils.writeDriveData(activity, gapi);
                break;
            case ActivityUtils.REQUEST_CODE_OPENER:
                if (data == null) { // If operation was canceled
                    return;
                }
                driveId = data.getParcelableExtra(
                        OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
                if (DEBUG) {
                    Log.d(TAG, driveId.encodeToString() + ", " + driveId.getResourceId() + ", " +
                            driveId.toInvariantString());
                }
                sm.setString(R.string.sm_google_drive_id, driveId.encodeToString());
                final GoogleApiClient finalGapi1 = gapi;
                new AlertDialog.Builder(activity)
                        .setTitle(R.string.sync_initial)
                        .setPositiveButton(R.string.sync_cloud_local, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                ActivityUtils.readDriveData(activity, finalGapi1);
                            }
                        })
                        .setNegativeButton(R.string.sync_local_cloud, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                ActivityUtils.writeDriveData(activity, finalGapi1);
                            }
                        })
                        .show();
        }
    }

    /* MISC */
    public static void openAbout(final Activity activity) {
        try {
            PackageInfo pInfo = activity.getPackageManager().getPackageInfo(
                    activity.getPackageName(), 0);
            new AlertDialog.Builder(activity)
                    .setTitle(R.string.app_name)
                    .setMessage(activity.getString(R.string.about_app_description, pInfo.versionName))
                    .setPositiveButton(R.string.website, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            launchWebsite(activity);
                        }
                    })
                    .setNegativeButton(R.string.help, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            ActivityUtils.openIntroVoluntarily(activity);
                        }
                    })
                    .show();
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void launchWebsite(Activity activity) {
        String url = activity.getString(R.string.website_url);
        CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
        CustomTabsIntent customTabsIntent = builder.build();
        try {
            customTabsIntent.launchUrl(activity, Uri.parse(url));
        } catch (Exception e) {
            // There is no way to view the website.
            activity.startActivity(new Intent(activity,
                    HomepageWebViewActivity.class));
        }
    }

    public static void openStream(Activity activity, String url) {
        Intent i = new Intent(activity, CumulusVideoPlayback.class);
        i.putExtra(CumulusVideoPlayback.KEY_VIDEO_URL, url);
        activity.startActivity(i);
    }

    public static void openIntroIfNeeded(Activity activity) {
        SettingsManager sm = new SettingsManager(activity);
        if(sm.getInt(R.string.sm_last_version) < LAST_GOOD_BUILD) {
            activity.startActivity(new Intent(activity, Intro.class));
            activity.finish();
        }
    }

    public static void openIntroVoluntarily(Activity activity) {
        activity.startActivity(new Intent(activity, Intro.class));
        activity.finish();
    }

    public static Class getMainActivity(Activity activity) {
        if(AppUtils.isTV(activity)) {
            return LeanbackActivity.class;
        }
        return MainActivity.class;
    }

    public static void handleMalformedChannelData(final Activity activity,
          final GoogleApiClient googleApiClient, ChannelDatabase.MalformedChannelDataException e) {
        // Give users the option to reset
        new AlertDialog.Builder(activity)
                .setTitle(R.string.chdb_issue_title)
                .setMessage(activity.getString(R.string.chdb_issue_info, e.getMessage()))
                .setPositiveButton(R.string.action_clear_local_data, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        ActivityUtils.deleteChannelData(activity, googleApiClient);
                        activity.startActivity(new Intent(activity, MainActivity.class));
                    }
                })
                .setNegativeButton(R.string.exit_app, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        activity.finish();
                    }
                })
                .show();
    }

    public static void exportM3uPlaylist(final Activity activity) {
        File dir = Environment.getExternalStorageDirectory();
        File userM3u = new File(dir.toString() + "/" + "cumulus_channels.m3u");
        int index = 0;
        Log.d(TAG, "Searching for viable file");
        while (userM3u.exists()) {
            userM3u = new File(dir.toString() + "/" + "cumulus_channels_" + index + ".m3u");
            Log.d(TAG, "Trying " + userM3u.getName());
            index++;
        }
        if (!dir.exists()) {
            Log.d(TAG, "Make directory? " + dir.mkdir());
        }
        try {
            Log.d(TAG, "To create: " + userM3u.getAbsolutePath());
            FileOutputStream out = new FileOutputStream(userM3u);
            Log.d(TAG, "Starting to write out data");
            out.write(ChannelDatabase.getInstance(activity).toM3u().getBytes());
            out.flush();
            out.close();
            Log.d(TAG, "Data written to " + userM3u.getAbsolutePath());
            Toast.makeText(activity, "M3U Playlist written to " +
                    userM3u.getCanonicalPath(), Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void onConnected(GoogleApiClient gapi) {
        mGoogleApiClient = gapi;
    }

    public static void onChannelsChanged(Context context) {
        // Send broadcast to update UI
        GoogleDriveBroadcastReceiver.changeStatus(context,
                GoogleDriveBroadcastReceiver.EVENT_DOWNLOAD_COMPLETE);
        // Re-request a TIF sync
        CumulusJobService.requestImmediateSync1(context,
                ActivityUtils.TV_INPUT_SERVICE.flattenToString(),
                CumulusJobService.DEFAULT_IMMEDIATE_EPG_DURATION_MILLIS,
                new ComponentName(context, CumulusJobService.class));
    }
}